/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/**
 *
 * $Id: ImageData.hpp,v 1.10 2009-05-13 07:18:17 amaula Exp $
 *
 * \file
 * \brief MaCI - Image Data encoder/decoder header.
 * \author Antti Maula <antti.maula@tkk.fi>
 */
#ifndef _MACI_INTERFACE_IMAGEDATA_HPP_
#define _MACI_INTERFACE_IMAGEDATA_HPP_

#include "ImageTypes.hpp"
#include "timestamp.hpp"
#include "MaCIData.hpp"
#include <stdio.h>
#include <map>
#include <vector>

namespace gim {
  namespace binbag{class CBinBag;}
}

namespace MaCI {
  namespace Image {

    class CImageContainer;


    /** Type to hide the BinBag details from ImageData interface users.
     */
    typedef gim::binbag::TBinBlob* TImageDataIterator;


    /** Type for storing SourceInfo element pointers.
     *
     */
    typedef std::map<unsigned int, const TSourceInfo *> TSourceInfoPtrArray;


    /** Type for storing SourceInfo elements.
     */ 
    typedef std::map<unsigned int, TSourceInfo> TSourceInfoMap;

    
    /** Image Data Decoder/Encoder.
     *
     */
    class CImageData : public CMaCIData
    {
    public:
      /** Constructor.
       *
       */
      CImageData(void);


      /** Destructor.
       *
       */
      ~CImageData(void);
      

      /** Copy constructor for ImageData. 
       *
       * The copy constructor duplicates the input object to maximum
       * depth (All containers are duplicated too). After a copy is
       * constructed, no dependencies to original Data element exist.
       *
       * @param[in] aImageData Reference to CImageData 
       *            container to copy.
       */
      CImageData(const CImageData &aImageData);

      

      /** Assignment operator for ImageData.
       *
       * The assignment operator duplicates the input object to
       * maximum depth (All containers are duplicated too). After a
       * copy is constructed, no dependencies to original Data element
       * exist.
       *
       * @param[in] aImageData Reference to CImageData 
       *            container to copy.
       */
      CImageData &operator=(const CImageData &aImageData);



      ///////////////////////////////////////////////////
      // Derived from 'CMaCIData', see description there.
      bool DecodeFrom(gim::binbag::CBinBag *aBinBag = NULL);
      void Reset();
      void Print(const int level) const;
      ///////////////////////////////////////////////////


      // Setter ocmmands
      /** Set Timestamp element.
       * 
       * \see Common::TTimestamp
       *
       * @param[in] aStamp      Timestamp element to set.
       * @return                'true' if no such element previously
       *                        exists, and a valid binbag::CBinBag backend exists.
       */
      bool SetTimestamp(const Common::TTimestamp &aStamp);


      /** Set Command element.
       *
       * Command elements must be accompanied by related dataelement
       * when required by commandtype. See the command enumerations
       * for a note about required datatype. (For example, 'SetSpeed'
       * command required a 'Speed' datatype after the command.
       * 
       * \see TCommand
       *
       * @param[in] aCmd        Command element to set.
       * @return                'true' if no such element previously
       *                        exists, and a valid binbag::CBinBag backend exists.
       */
      bool SetCommand(const TCommand &aCmd);


      /** Add a new Image data element.
       * 
       * This function ADDS a new Image element to container.
       * Container may contain multiple images with different types at
       * the same time. Images may be fetched from the container by
       * calling GetImage function.
       *
       * @param[in] aSourceIndex Source index to use.
       * @param[in] aImageData  ImageData container to insert.
       * @return                'true' when adding image was successfully,
       *                         'false' on failure.
       */
      bool AddImage(const unsigned int aSourceIndex, 
                    const CImageContainer &aImageData);
      

      /** Add SourceInfo element.
       *
       * This function adds a new SourceInfo element to container. No
       * checks are made about the legality of containers, for
       * example, you can add the same source_index twice. Client will
       * only use the latter one.
       *
       * @param[in] aSourceInfo SourceInfo to insert.
       * @return                'true' when adding image was successfully,
       *                         'false' on failure.
       *
       */
      bool AddSourceInfo(const TSourceInfo &aSourceInfo);

            
      // Getter commands
      /** Get pointer to Common::TTimestamp element (if such exists).
       *
       * \see Common::TTimestamp
       * 
       * @return                Constant pointer to timestamp
       *                        element if such element exists
       *                        in the container. If the element 
       *                        doesn't exist, NULL is returned.
       */
      const Common::TTimestamp *GetTimestamp(void) const;


      /** Get Image(s) from container.
       *
       * This function fetches images from the container. With proper
       * parameters, this function is able to fetch all the carried
       * images in sequence.
       *
       * \note Per default, this function only stores the address of
       * the currently stored data, so if you don't duplicate the data
       * element, you will have to maintain this (CImageData) object
       * intact as long as the data needs to be used.
       *
       * @param[out] aImageData  Reference to container which will
       *                         carry the data.
       * @param[out] aImageIteratorPtr Pointer to iterator used for
       *                         storing the current position in the 
       *                         image sequence. If this is NULL, the first
       *                         image in the container will be returned
       *                         on every call. If this is non-null, its
       *                         state will be updated after each call.
       *                         The value of the pointed iterator must
       *                         be NULL on the first call.
       * @param[in] aDuplicateData If this is set to 'true', the function call
       *                         will duplicate the contained data to
       *                         the provided CImageContainer reference. After this,
       *                         the CImageContainer is totally independent and
       *                         can be stored freely. If this is left 
       *                         to value 'false', the returned data still
       *                         points to contents of this ImageData instance,
       *                         hence this object must be valid
       *                         as long as the pointed by value is required.
       * @return                 'true', when data was succesfully extracted and
       *                         stored to the provided CImageContainer container.
       *                         'false' in case of an error; No (more) 
       *                         images available, or object in invalid state 
       *                         (Must be Valid and ReadOnly)
       */
      bool GetImage(CImageContainer &aImageData,
                    TImageDataIterator *aImageIteratorPtr = NULL,
                    bool aDuplicateData = false) const;
      

      /** Return true if this is a Image container (Contains atleast
       * one Image)
       *
       * @return                'True' if contains images, otherwise 'false'.
       */
      inline bool IsImageContainer(void) const {
        return (iFirstImageInfoPtr != NULL);
      }
      
      /** Return number of images stored in this container.
       *
       * @return                Number of images in this container.
       */
      inline unsigned int GetImageCount(void) const 
      {
        return iImageCount;
      }
      
      
      /** Get constant pointer to TCommand element (if such exists).
       *
       * \see TCommand
       * 
       * @return                Constant pointer to command
       *                        element if such element exists
       *                        in the container. If the element 
       *                        doesn't exist, NULL is returned.
       */
      const TCommand *GetCommand(void) const;

      
      /** Get pointer to imagesource by imagesource index.
       *
       * This function returns a pointer to sourceinfo by ImageSource
       * index. Note that this may be different from the order of
       * received elements. ImageSource index corresponds to the
       * 'sourceindex' value stored in the TSourceInfo element.
       *
       * @param[in] aInfoIndex  SourceIndex to get pointer to.
       * @return                NULL-pointer if no such source exists,
       *                        
       * 
       *
       */
      const TSourceInfo *GetSourceInfo(const unsigned int aInfoIndex) const;


      /** Returns a SourceInfo map containing all the SourceInfo
       * elements in a std::map.
       *
       * @return                Data of all SourceInfo containers in single std::map container.
       */
      TSourceInfoMap GetSourceInfoMap(void) const;

      
      /** Return true if this is a SourceInfo container (Contains
       * atleast one TSourceInfo element)
       *
       * @return 'True' if contains sourceinfos, otherwise 'false'.
       */
      inline bool IsSourceInfoContainer(void) const {
        return (iCommandPtr != NULL &&
                iCommandPtr->cmd == KCommandSetSourceInfoArray);
      }

    private:
      bool iValid;
      
      const Common::TTimestamp *iTimestampPtr; ///< Pointer to Timestamp
      const TCommand *iCommandPtr; ///< Pointer to command if any.

      const gim::binbag::TBinBlob *iFirstImageInfoPtr;
      unsigned int iImageCount;

      const TSourceInfo *iFirstSourceInfoPtr; ///< Container 'First' source.
      TSourceInfoPtrArray iSourceInfoPtrArray; ///< Pointer array to Source elements.
    };
  }
}
#endif //_MACI_INTERFACE_IMAGEDATA_HPP_
